package ansible

import (
	"fmt"
	"github.com/pkg/sftp"
	"golang.org/x/crypto/ssh"
	"log"
	"net"
	"strings"
)

// 通过用户名和密码生成一个配置文件
func GetSshConfigByPassword(user string, passwrod string) *ssh.ClientConfig {
	sshConfig := &ssh.ClientConfig{
		User: user,
		Auth: []ssh.AuthMethod{
			ssh.Password(passwrod),
		},
		HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
			return nil
		},
	}
	return sshConfig
}

// 通过*ssh.Client 执行命令
func SSHExecCmd(client *ssh.Client, cmd string) ([]byte, error) {
	session, err := client.NewSession()
	defer session.Close()
	if err != nil {
		return nil, fmt.Errorf("Failed to create session: %s", err)
	}

	out, err := session.CombinedOutput(cmd)
	if err != nil {
		return nil, fmt.Errorf("cmd fail")
	}
	return out, err
}

// 复制字节数组到远程服务器上
func CopyByteToRemote(client *ssh.Client, byteStream []byte, remoteFilePath string) error {
	sftpClient, err := sftp.NewClient(client)
	if err != nil {
		log.Println("sftp.NewClient occure err %s", err)
		return err
	}
	defer sftpClient.Close()
	dstFile, err := sftpClient.Create(remoteFilePath) //创建文件夹
	if err != nil {
		log.Fatal(err)
		return err
	}
	defer dstFile.Close()
	dstFile.Write(byteStream)
	log.Println("copy byteStream to remote server finished!")
	return nil
}

//通过ssh.ClientConfig创建一个ssh连接
func GetSshClient(host string, port int, sshConfig *ssh.ClientConfig) (*ssh.Client, error) {
	addr := fmt.Sprintf("%s:%d", host, port)
	fmt.Println(addr)
	client, err := ssh.Dial("tcp", addr, sshConfig)
	if err != nil {
		return nil, fmt.Errorf("Failed to dial:%s", err)
	} else if client == nil {
		panic("get client client failure")
	}
	return client, nil
}

// Connect host by ssh, than run cmd with ansible
func AnsibleCmd(dBoxHost string, port int, hostIP string, user string, password string) error {
	log.Println("start ansibleCmd")
	sshConfig := GetSshConfigByPassword(user, password)
	sshClient, err := GetSshClient(dBoxHost, port, sshConfig)
	if err != nil {
		log.Println("get ssh client happend an erro: %s", err)
		return err
	}
	defer sshClient.Close()
	ansibleCmd := fmt.Sprintf("ansible %s -m command -a 'systemctl start kubelet'", hostIP)
	log.Println("ansibleCmd:%s", ansibleCmd)
	out, err := SSHExecCmd(sshClient, ansibleCmd)
	if err != nil {
		log.Println("Exec command happend an error: %s", err)
		return err
	}
	log.Println(string(out))
	return nil
}

//  Ansible playbook
func AnsiblePlayBook(dBoxHost string, port int, hosts []string, user string, password string) error {
	// 1. 生成ansible 任务文件
	log.Println("ansibleRun 1: get PlayBook")
	cmd := "systemctl restart kubelet"
	hostsStr := strings.Join(hosts, " ")
	palyBook := GeneratePlayBook(hostsStr, cmd)

	// 2. 后去一个ssh client
	log.Println("ansibleRun 2: get sshClient")
	sshConfig := GetSshConfigByPassword(user, password)
	sshClient, err := GetSshClient(dBoxHost, port, sshConfig)
	if err != nil {
		log.Println("get ssh client happend an erro: %s", err)
		return err
	}
	defer sshClient.Close()

	//3.通过sftp传输文件
	log.Println("ansibleRun 3: sftp run")
	if err != nil {
		log.Println("sftp.NewClient occure err %s", err)
		return err
	}
	CopyByteToRemote(sshClient, palyBook, "/root/playbook.yaml")

	//4.通过session执行命令行
	log.Println("ansibleRun 4:exec cmd ansible-playbook")
	cmd = "ansible-playbook /root/playbook.yaml"
	out, err := SSHExecCmd(sshClient, cmd)
	if err != nil {
		log.Println("Exec command happend an error: %s", err)
		return err
	}
	log.Println(string(out))
	return nil
}
